/**
 * Licensed to Open-Ones Group under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Open-Ones Group licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a
 * copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package openones.ipresenter.android.view;

import java.io.IOException;
import java.net.Socket;

import openones.ipresenter.android.R;
import openones.ipresenter.android.dao.ConnectionData;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

/**
 * This activity is used for manipulating with Wifi.
 * Start Presentation when a connection is made.
 * @author OOG Member
 */
public class ScanWifiActivity extends Activity {
    /**
     * Constant tells Wifi is not supported by the device.
     */
    private static final int WIFI_UNAVAILABLE = 0;
    
    /**
     * Constant tells Wifi is disabled.
     */
    private static final int WIFI_DISABLED = 1;
    
    /**
     * Constant tells Wifi is enabled.
     */
    private static final int WIFI_ENABLED = 2;
    
    
    /**
     * Constant tells there's no connection with access point.
     */
    private static final int NETWORK_NOT_CONNECTED = 0;
    
    /**
     * Constant tells a connection with an access point is established.
     */
    private static final int NETWORK_CONNECTED = 1;
    
    
    /**
     * Constant tells there's not connection with server (the PC where Powerpoint is presented).
     */
    private static final int SERVER_NOT_CONNECTED = 0;
    
    /**
     * Constant tells a connection with server is established (the PC where Powerpoint is presented).
     */
    private static final int SERVER_CONNECTED = 1;
    
    private static final int BRIGHTNESS_DIALOG = 1;
    
    
    /**
     * The current wifi state (unavailable, disabled, enabled).
     */
    private int mWifiState;

    /**
     * The current connection state (not connected, connected) with access point.
     */
    private int mNetworkConnectionState;
       
    /**
     * The current connection state (not connected, connected) with server.
     */
    private int mServerConnectionState;
    
    
    /**
     * The TextView shows the current network (access point) name.
     */
    private TextView tvConnectedNetwork;
    
    /**
     * The TextView shows the current network IP address.
     */
    private TextView tvReceivedIP;
    
    /**
     * The TextView shows the current connected server (ip, port).
     */
    private TextView tvConnectedServer;
    
    /**
     * Wifi manager.
     */
    private WifiManager mWifiManager;
    
    /**
     * Wifi socket.
     */
    private Socket mSocket;
    
    /**
     * The progress dialog displayed when connecting task is in progress.
     */
    private ProgressDialog mProgressDialog;
    
    
    /**
     * Called when the activity is first created.
     * @param savedInstanceState Information about the last state.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.scanwifi);
        
        setupUI();
        setupWifi();
    }
    
    /**
     * Setup the views on the layout.
     * Set the OnClickListener for the buttons.
     * Set the OnItemClickListener for the items on the lvNetworks.
     */
    void setupUI() {
        Button btConnectToServer = (Button) findViewById(R.id.scanwf_btConnectToServer);
        if (btConnectToServer != null) {
            btConnectToServer.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    connectToServer();
                }
            });
        }
        
        Button btStartPresentation = (Button) findViewById(R.id.scanwf_btStartPresentation);
        if (btStartPresentation != null) {
            btStartPresentation.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    showDialog(BRIGHTNESS_DIALOG);
                }
            });
        }
        
        tvConnectedNetwork = (TextView) findViewById(R.id.scanwf_tvConnectedNetwork);
        tvReceivedIP = (TextView) findViewById(R.id.scanwf_tvReceivedIP);
        tvConnectedServer = (TextView) findViewById(R.id.scanwf_tvConnectedServer);
        
        mProgressDialog = null;
    }
    
    /**
     * If a network connection is OK, allow user to connect to a server on that network.
     */
    void connectToServer() {
        if (mNetworkConnectionState == NETWORK_NOT_CONNECTED) {
            Toast.makeText(this, "Network is not connected.\n"
                      + "You must connect to network first", Toast.LENGTH_SHORT).show();
            return;
        }
        
        // If user wants to cancel current connection and start another one.
        // Cancel current connection if it exists.
        if (mServerConnectionState == SERVER_CONNECTED) {
            mServerConnectionState = SERVER_NOT_CONNECTED;
            closeSocket(); 
        }
        
        //get IP and port
        EditText etIP = (EditText) findViewById(R.id.scanwf_etIP);
        EditText etPort = (EditText) findViewById(R.id.scanwf_etPort);
        
        //check IP format regular expression
        String ip = (etIP.getText()).toString();
        String strPort = (etPort.getText()).toString();
        int port = 0;
        try {
            port = Integer.parseInt(strPort);           
        } catch (Exception e) {
            port = 0;
        }
        
        mProgressDialog = ProgressDialog.show(this, "Connecting", "Please wait ...");
        mProgressDialog.setCancelable(true);
        doConnectToServerTask(ip, port);
    }
    
    /**
     * Used AsynTask to do connecto to server in another thread.
     * @param ip IP of server.
     * @param port Port of server application.
     */
    void doConnectToServerTask(final String ip, final int port) {
        AsyncTask<Void, Void, Void> connectTask = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                //connect to server
                try {
                    mServerConnectionState = SERVER_CONNECTED;
                    mSocket = new Socket(ip, port);      
                } catch (Exception e) {
                    mServerConnectionState = SERVER_NOT_CONNECTED;
                    
                    ScanWifiActivity.this.runOnUiThread(new Runnable() {
                        public void run() {
                            Toast.makeText(ScanWifiActivity.this, 
                                    "Connect to server fails", Toast.LENGTH_SHORT).show();
                        }
                    });
                    
                    closeSocket();
                    
                }
                return null;
            }
       
            @Override
            protected void onPostExecute(Void result) {
                if (mProgressDialog != null) {
                    mProgressDialog.dismiss();
                    
                if (mSocket != null && mServerConnectionState == SERVER_CONNECTED) {
                    // Set the tvConnectedServer.
                    EditText etIP = (EditText) findViewById(R.id.scanwf_etIP);
                    EditText etPort = (EditText) findViewById(R.id.scanwf_etPort);
                    
                    String strConnectedServer = etIP.getText().toString() + " : " + etPort.getText().toString();
                    tvConnectedServer.setText(strConnectedServer);
                    
                    // Show the alert dialog to confirm success connection
                    AlertDialog.Builder builder = new AlertDialog.Builder(ScanWifiActivity.this);
                    builder.setMessage("Successfully connected to server.\n"  
                                + "You may start presentation now.")
                           .setCancelable(false)
                           .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                               public void onClick(DialogInterface dialog, int id) {
                                   dialog.cancel();
                               }
                           });
                    AlertDialog alert = builder.create();
                    alert.show();                   
                    } 
                } else {
                    // Set the tvConnectedServer to indicate that no server connection is made.
                    tvConnectedServer.setText("NOT CONNECTED");
                }
            
            }       
        };
        connectTask.execute();
    }
    
    /**
     * If a connection is made successfully, allow user to start presentation.
     * Go to PresentActivity.
     */
    void startPresentation() {
        if (mServerConnectionState == SERVER_NOT_CONNECTED || mSocket == null) {
            tvConnectedServer.setText("");
            
            Toast.makeText(this, "Server is not connected.\n"
                    + "You must connect to server before you can start", Toast.LENGTH_SHORT).show();
            return;
        }
        
        Intent intent = new Intent(ScanWifiActivity.this, PresentActivity.class);
        intent.putExtra("connectionType", PresentActivity.CONNECTION_TYPE_WIFI);
        ConnectionData connectionData = ((ConnectionData) getApplicationContext());
        connectionData.setWifiSocket(mSocket);
        startActivity(intent);
        finish();
    }
    
    /**
     * Setup wifi and set the connection state.
     * Check existing network connection in case your device is already connected to a network.
     */
    void setupWifi() {
        mNetworkConnectionState = NETWORK_NOT_CONNECTED;
        mServerConnectionState = SERVER_NOT_CONNECTED;
        
        if (mSocket != null) {
            mSocket = null;
        }
           
        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        if (mWifiManager == null) {
            mWifiState = WIFI_UNAVAILABLE;
            Toast.makeText(this, "Wifi is unavailable", Toast.LENGTH_SHORT).show();
            
        } else {
            if (mWifiManager.isWifiEnabled()) {
                mWifiState = WIFI_ENABLED;
                checkExistingNetworkConnection();
            } else {
                mWifiState = WIFI_DISABLED;
                Toast.makeText(this, "Wifi is disabled.\n"
                        + "You must enable Wifi to work", Toast.LENGTH_SHORT).show();
            }
        }
    }

    
    /**
     * Check if this device is already connect to an access point.
     * If yes, show information about this network connection.
     */
    void checkExistingNetworkConnection() {
        try {
            ConnectivityManager connectivityManager = 
                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            
            if (connectivityManager != null) {
                // Get the first active network interface this phone can find.
                // Return null if none of the interfaces are connected.
                
                NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
         
                // This is for Wifi connectivity.
                // 3G will be consulted later.
                // Check if there is a network connection.
                if (activeNetworkInfo != null && activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI 
                           && activeNetworkInfo.isConnected()) {
                    mNetworkConnectionState = NETWORK_CONNECTED;
                    
                    // Get information on the active connection's status.
                    if (mWifiManager != null) {
                       WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
                       if (wifiInfo != null) {
                           // Get the SSID (public name) of the current active network
                           String ssid = wifiInfo.getSSID();
                           if (ssid != null) {
                               //ssid = ssid.replace("\"", "");
                               tvConnectedNetwork.setText(ssid);
                           }
                           
                           // Get the IP received by the network.
                           int ip = wifiInfo.getIpAddress();
                           String strIP =  String.format("%d.%d.%d.%d", 
                                   (ip & 0xff), 
                                   (ip >> 8 & 0xff),
                                   (ip >> 16 & 0xff),
                                   (ip >> 24 & 0xff));
                           
                           tvReceivedIP.setText(strIP);
                       }
                    }

                    Toast.makeText(this, "Network is connected.\n"
                            + "You may connect to server now", Toast.LENGTH_SHORT).show();
                    
                } else {
                    mNetworkConnectionState = NETWORK_NOT_CONNECTED;
                    
                    tvConnectedNetwork.setText("NOT CONNECTED");
                    tvReceivedIP.setText("");
                    
                    Toast.makeText(this, "Network is not connected.\n"
                          + "You must connect to network first", Toast.LENGTH_SHORT).show();
                }
            }
        } catch (Exception e) {
            // This is an issue 10047 on XD Android.
            mNetworkConnectionState = NETWORK_CONNECTED;
        }
        
  
    }
    

    /**
    * Create Option menu.
    * @param menu The menu to create.
    * @return boolean Indicate if the menu was created successfully.
    */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.scanwifi, menu);
        return true;
    }
    
    /**
     * Called when an item on the menu is selected.
     * @param item The menu item being selected.
     * @return True if the OnItemClick is handled.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_mainmenu:
            // Close socket.
            closeSocket();
            
            // Return to MainMenuActivity.
            Intent intentMainMenu = new Intent(ScanWifiActivity.this, MainMenuActivity.class);
            startActivity(intentMainMenu);
            finish();
            return true;
        case R.id.menu_bluetooth:
            // Close socket.
            closeSocket();
            
            // Switch to ScanBluetooth mode.
            Intent intentScanBluetooth = new Intent(ScanWifiActivity.this, ScanBluetoothActivity.class);
            startActivity(intentScanBluetooth);
            finish();
            return true;
        default:
            break;
        }
        return false;
    }
    
    /**
     * Close the socket if it exists.
     */
    public void closeSocket() {
        // Close socket
        if (mSocket != null) {
            try {
                mSocket.close();
            } catch (IOException e) {
                ScanWifiActivity.this.runOnUiThread(new Runnable() {
                    public void run() {
                        Toast.makeText(ScanWifiActivity.this, 
                                "Close connection fails", Toast.LENGTH_SHORT).show();
                    }
                });
            }
            mSocket = null;
        }
        
    }
    
 // a dialog appears after user tap Brightness item 
    @Override
    protected Dialog onCreateDialog(int id) {
        // TODO Auto-generated method stub
        switch (id) {
        case BRIGHTNESS_DIALOG:
            return new AlertDialog.Builder(ScanWifiActivity.this).setTitle(
                    "Turn on battery saver mode?").setPositiveButton("OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                int whichButton) {
                            /* User clicked OK so do some stuff */
                            setBrightness();
                            startPresentation();
                        }
                    }).setNegativeButton("Cancel",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                int whichButton) {
                            /* User clicked Cancel so do some stuff */
                            startPresentation();
                        }
                    }).create();
        }
        return null;
    }
    
    // set the brightness of application is 1
    public void setBrightness() {
        android.provider.Settings.System.putInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, 1);
        float backLightValue = (float) 1 / 100;
        WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
        layoutParams.screenBrightness = backLightValue;
        getWindow().setAttributes(layoutParams);
    }
}
